import { defineComponent, h, PropType, isVNode } from 'vue'
import { usePrefix, useRegistry, useInject } from '../../hooks'
import {
  isStr,
  isFn,
  makeNumericProp,
  makeNumberProp,
  makeStringProp,
  uid,
} from '@/shared'
import type {
  StrokeLinejoin,
  StrokeLinecap,
  IconTheme,
  // IIconBase,
  ISvgIconProps,
  IDesignerAppConfig,
} from '@/core'
import './styles.less'

const iconWidgetProps = {
  infer: {
    required: true as const,
  },
  fill: [String, Array] as PropType<string> | PropType<string[]>,
  size: makeNumericProp(),
  strokeWidth: makeNumberProp(),
  strokeLinecap: makeStringProp<StrokeLinecap>(),
  strokeLinejoin: makeStringProp<StrokeLinejoin>(),
  theme: makeStringProp<IconTheme>(),
}

// 属性转换函数
export function IconConverter(
  id: string,
  icon: any,
  config: IDesignerAppConfig,
): ISvgIconProps {
  let configIconFill: string[] = config.followSystem
    ? []
    : typeof config.iconFill === 'string'
    ? [config.iconFill]
    : config.iconFill

  let fill: string[] =
    typeof icon.iconFill === 'string'
      ? [icon.iconFill]
      : icon.iconFill || configIconFill

  const colors: string[] = []

  const theme: IconTheme = icon.iconTheme || config.iconTheme

  switch (theme) {
    case 'outline':
      colors.push(typeof fill[0] === 'string' ? fill[0] : 'currentColor')
      colors.push('none')
      colors.push(typeof fill[0] === 'string' ? fill[0] : 'currentColor')
      colors.push('none')
      break
    case 'filled':
      colors.push(typeof fill[0] === 'string' ? fill[0] : 'currentColor')
      colors.push(typeof fill[0] === 'string' ? fill[0] : 'currentColor')
      colors.push('#FFF')
      colors.push('#FFF')
      break
    case 'two-tone':
      colors.push(typeof fill[0] === 'string' ? fill[0] : 'currentColor')
      colors.push(
        typeof fill[1] === 'string'
          ? fill[1]
          : config.iconColor.twoTone.twoTone,
      )
      colors.push(typeof fill[0] === 'string' ? fill[0] : 'currentColor')
      colors.push(
        typeof fill[1] === 'string'
          ? fill[1]
          : config.iconColor.twoTone.twoTone,
      )
      break
    case 'multi-color':
      colors.push(typeof fill[0] === 'string' ? fill[0] : 'currentColor')
      colors.push(
        typeof fill[1] === 'string'
          ? fill[1]
          : config.iconColor.multiColor.outFillColor,
      )
      colors.push(
        typeof fill[2] === 'string'
          ? fill[2]
          : config.iconColor.multiColor.innerStrokeColor,
      )
      colors.push(
        typeof fill[3] === 'string'
          ? fill[3]
          : config.iconColor.multiColor.innerFillColor,
      )
      break
  }

  return {
    iconSize: icon.iconSize || config.iconSize,
    strokeWidth: icon.strokeWidth || config.strokeWidth,
    strokeLinecap: icon.strokeLinecap || config.strokeLinecap,
    strokeLinejoin: icon.strokeLinejoin || config.strokeLinejoin,
    colors,
    id,
  }
}

export const IconWidget = defineComponent({
  props: iconWidgetProps,
  setup(props, { attrs }) {
    const prefix = usePrefix('icon-widget')
    const registry = useRegistry()
    const appConfig = useInject()
    const id = uid()
    const width =
      (attrs.style as any)?.width || props.size || appConfig.iconSize
    const height =
      (attrs.style as any)?.height || props.size || appConfig.iconSize
    const takeIcon = (infer: any): any => {
      if (isStr(infer)) {
        const finded = registry.getDesignerIcon(infer)
        if (finded) {
          return takeIcon(finded)
        }
        return <img src={infer} width={width} height={height} />
      } else if (isFn(infer)) {
        const svgProps = IconConverter(
          id,
          {
            iconFill: props?.fill,
            iconSize: props?.size,
            strokeWidth: props?.strokeWidth,
            strokeLinecap: props?.strokeLinecap,
            strokeLinejoin: props?.strokeLinejoin,
            iconTheme: props?.theme,
          },
          appConfig,
        )
        return h(infer, svgProps)
      } else if (isVNode(infer)) {
        if (infer.type === 'path' || infer.type === 'g') {
          return (
            <svg
              viewBox="0 0 1024 1024"
              height={height}
              width={width}
              fill="currentColor"
              focusable="false"
              aria-hidden="true"
            >
              {infer}
            </svg>
          )
        } else if (infer.type === 'svg') {
          return h(infer, {
            width,
            height,
            fill: 'currentColor',
            viewBox: infer.props?.viewBox || '0 0 1024 1024',
            focusable: 'false',
            'aria-hidden': 'true',
          })
        }
      } else {
        return h(infer)
      }
    }
    return () => <span class={prefix}>{takeIcon(props.infer)}</span>
  },
})
